package com.example.observer.dubbo;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;
import java.util.function.Predicate;
import java.util.stream.Stream;

public abstract class AbstractEventDispatcher implements EventDispatcher{



    private final ConcurrentMap<Class<? extends Event>, List<EventListener>> listenerCache = new ConcurrentHashMap<>();



    private Executor executor;


    public AbstractEventDispatcher(Executor executor) {
        if (executor == null) {
            throw new NullPointerException("executor must not be null");
        }
        this.executor = executor;
    }


    public Executor getExecutor() {
        return executor;
    }

    @Override
    public void addEventListener(EventListener<?> listener) throws NullPointerException, IllegalArgumentException {
        // assert
        Listenable.assertListener(listener);
        // findEventType
        Class<? extends Event> eventType = EventListener.findEventType(listener);
        if (eventType!=null) {
            List<EventListener> listeners = listenerCache.computeIfAbsent(eventType, r -> new LinkedList<>());
            if (!listeners.contains(listener)) {
                listeners.add(listener);
            }
            // sort
            Collections.sort(listeners);
        }
    }

    @Override
    public void removeEventListener(EventListener<?> listener) throws NullPointerException, IllegalArgumentException {

    }


    @Override
    public void dispatch(Event event) {
        Executor executor = getExecutor();
        executor.execute(()->{
            sortedListeners(entry -> entry.getKey().isAssignableFrom(event.getClass()))//  a  extends A    子类的事件也会触发父类的监听器
                    .forEach(listener -> {
                        //handler the event
                        listener.onEvent(event);
                    });
        });
    }

    protected Stream<EventListener> sortedListeners(Predicate<Map.Entry<Class<? extends Event>, List<EventListener>>> predicate) {
        return listenerCache.entrySet().stream()
                .filter(predicate)
                .map(Map.Entry::getValue)
                .flatMap(Collection::stream)
                .sorted();
    }
}
